<script setup lang="tsx">
// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 模块导入 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

import { NButton, NPopconfirm } from 'naive-ui';
import type { Ref } from 'vue';
import { nextTick, ref } from 'vue';
import { useBoolean } from '@sa/hooks';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales';
import { transDeleteParams } from '@/utils/common';
import { fetchCjTaskDownloadTemplate, fetchDeleteCjTask, fetchGetCjTaskPage } from '@/service/api';
import { useDict } from '@/hooks/business/dict';
import type { FlatResponseData } from '~/packages/axios/src/type';
import TaskSearch from './modules/task-search.vue';
import type { OperateType } from './modules/task-operate-drawer.vue';
import TaskOperateDrawer from './modules/task-operate-drawer.vue';
import TaskImportDataModal from './modules/task-import-data-modal.vue';

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 组件名称 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

defineOptions({
  name: 'CjTaskPage'
});

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 组合式函数 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const appStore = useAppStore();

const { hasAuth } = useAuth();

const { dictLabel, dictTag } = useDict();

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 父子传参 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架模型 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const operateType = ref<OperateType>('add');

const editingData: Ref<Api.Sampling.Task | null> = ref(null);

const { columns, columnChecks, resetAllColumns, data, loading, getData, getDataByPage, mobilePagination, searchParams, resetSearchParams } = useTable(
  {
    apiFn: (params: Api.Sampling.TaskSearchParams): Promise<FlatResponseData<Api.Common.PaginatingQueryRecord<Api.Sampling.Task>>> => {
      return new Promise((resolve, reject) => {
        fetchGetCjTaskPage(params)
          .then(res => {
            if (!res.error && res.data) {
              // 修正某些列按值自适应

              res.data.records.forEach((item: Api.Sampling.Task) => {
                item.orgName = `${item.provinceCityCountyInfo?.provinceName}${item.provinceCityCountyInfo?.cityName}${item.provinceCityCountyInfo?.countyName}`;
                item.soilTypeLabel = dictLabel('cj_soil_type', item.soilType);

                if (item.cropTypeManual) {
                  item.cropTypeLabel = item.cropTypeManual;
                } else {
                  item.cropTypeLabel = dictLabel('cj_crop_type', item.cropType);
                }
              });
              // 自适应列
              nextTick(() => {
                updateColumnsWidth(res.data);
              });
            }
            resolve(res);
          })
          .catch(err => {
            reject(err);
          });
      });
    },
    showTotal: true,
    apiParams: {
      page: 1,
      pageSize: 20,
      projectId: '',
      year: '',
      samplingType: '',
      taskStatus: '',
      provinceName: '',
      cityName: '',
      countyName: '',
      town: ''
    },
    columns: () => [
      {
        key: 'index',
        title: $t('common.index'),
        width: 64,
        align: 'center',
        fixed: 'left'
      },
      {
        key: 'projectName',
        title: $t('page.sampling.task.projectId'),
        align: 'left',
        titleAlign: 'center',
        width: 77,
        fixed: 'left'
      },
      {
        key: 'year',
        title: $t('page.sampling.task.year'),
        align: 'center',
        titleAlign: 'center',
        width: 77,
        fixed: 'left'
      },
      {
        key: 'positionType',
        title: $t('page.sampling.task.positionType'),
        align: 'center',
        titleAlign: 'center',
        width: 77,
        fixed: 'left',
        render: row => dictLabel('cj_position_type', row.positionType)
      },
      {
        key: 'samplingType',
        title: $t('page.sampling.task.samplingType'),
        align: 'center',
        titleAlign: 'center',
        width: 101,
        fixed: 'left',
        render: row => dictLabel('cj_sampling_type', row.samplingType)
      },
      {
        key: 'taskStatus',
        title: $t('page.sampling.task.taskStatus'),
        align: 'center',
        titleAlign: 'center',
        width: 130,
        fixed: 'left',
        render: row => dictTag('cj_task_status', row.taskStatus)
      },
      {
        key: 'orgName',
        title: $t('page.sampling.task.orgId'),
        align: 'left',
        titleAlign: 'center',
        fixed: 'left',
        width: 77
      },
      {
        key: 'code',
        title: '行政区划',
        titleAlign: 'left',
        children: [
          {
            key: 'code',
            title: $t('page.sampling.task.code'),
            align: 'left',
            titleAlign: 'center',
            width: 77
          },
          {
            key: 'provinceName',
            title: $t('page.sampling.task.province'),
            titleAlign: 'center',
            align: 'center',
            width: 34
          },
          {
            key: 'cityName',
            title: $t('page.sampling.task.city'),
            align: 'center',
            titleAlign: 'center',
            width: 34
          },
          {
            key: 'countyName',
            title: $t('page.sampling.task.county'),
            align: 'center',
            titleAlign: 'center',
            width: 49
          },
          {
            key: 'town',
            title: $t('page.sampling.task.town'),
            align: 'center',
            titleAlign: 'center',
            width: 49
          },
          {
            key: 'village',
            title: $t('page.sampling.task.village'),
            align: 'center',
            titleAlign: 'center',
            width: 49
          },
          {
            key: 'team',
            title: $t('page.sampling.task.team'),
            align: 'center',
            titleAlign: 'center',
            width: 49
          }
        ]
      },
      {
        key: 'wgs84Longitude',
        title: '点位坐标',
        titleAlign: 'left',
        children: [
          {
            key: 'wgs84Longitude',
            title: $t('page.sampling.task.wgs84Longitude'),
            align: 'right',
            titleAlign: 'center',
            width: 49
          },
          {
            key: 'wgs84Latitude',
            title: $t('page.sampling.task.wgs84Latitude'),
            align: 'right',
            titleAlign: 'center',
            width: 49
          },
          {
            key: 'wgs84Altitude',
            title: $t('page.sampling.task.wgs84Altitude'),
            align: 'right',
            titleAlign: 'center',
            width: 49
          }
        ]
      },
      {
        key: 'landUse',
        title: '土壤信息',
        titleAlign: 'left',
        children: [
          {
            key: 'landUse',
            title: $t('page.sampling.task.landUse'),
            align: 'center',
            titleAlign: 'center',
            width: 104,
            render: row => dictLabel('cj_land_use', row.landUse)
          },
          {
            key: 'protectionStrategy',
            title: $t('page.sampling.task.protectionStrategy'),
            align: 'center',
            titleAlign: 'center',
            width: 77,
            render: row => dictLabel('cj_protection_strategy', row.protectionStrategy)
          },
          {
            key: 'soilTypeLabel',
            title: $t('page.sampling.task.soilType'),
            align: 'center',
            titleAlign: 'center',
            width: 77
          },
          {
            key: 'soilClass',
            title: $t('page.sampling.task.soilClass'),
            align: 'center',
            titleAlign: 'center',
            width: 77,
            render: row => dictLabel('cj_soil_class', row.soilClass)
          },
          {
            key: 'subClass',
            title: $t('page.sampling.task.subClass'),
            align: 'center',
            titleAlign: 'center',
            width: 77,
            render: row => dictLabel('cj_sub_class', row.subClass)
          },
          {
            key: 'soilMaterial',
            title: $t('page.sampling.task.soilMaterial'),
            align: 'center',
            titleAlign: 'center',
            width: 77,
            render: row => dictLabel('cj_soil_material', row.soilMaterial)
          }
        ]
      },
      {
        key: 'cropType',
        title: '主产农作物',
        titleAlign: 'left',
        children: [
          {
            key: 'mainCrop',
            title: $t('page.sampling.task.mainCrop'),
            align: 'center',
            titleAlign: 'center',
            width: 91,
            render: row => dictLabel('cj_main_crop', row.mainCrop)
          },
          {
            key: 'cropTypeLabel',
            title: $t('page.sampling.task.cropType'),
            align: 'center',
            titleAlign: 'center',
            width: 77
          }
        ]
      },
      {
        key: 'operate',
        title: $t('common.operate'),
        align: 'center',
        width: 100,
        minWidth: 100,
        fixed: 'right',
        render: row => (
          <div class="flex-center gap-8px">
            {hasAuth('cj:task:update') && (
              <NButton type="primary" quaternary size="small" onClick={() => edit(row)}>
                {$t('common.edit')}
              </NButton>
            )}
            {hasAuth('cj:task:delete') && (
              <NPopconfirm onPositiveClick={() => handleDelete(row.id)}>
                {{
                  default: () => $t('common.confirmDelete'),
                  trigger: () => (
                    <NButton type="error" quaternary size="small">
                      {$t('common.delete')}
                    </NButton>
                  )
                }}
              </NPopconfirm>
            )}
          </div>
        )
      }
    ]
  }
);

const { drawerVisible, openDrawer, checkedRowKeys, onDeleted, onBatchDeleted } = useTableOperate(data, getData);

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务模型 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

const { bool: importDataModalVisible, setTrue: showImportDataModal } = useBoolean();

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架方法 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

function handleAdd() {
  operateType.value = 'add';
  openDrawer();
}

function edit(item: Api.Sampling.Task) {
  operateType.value = 'edit';
  editingData.value = { ...item };
  openDrawer();
}

async function handleDelete(id: string) {
  const { error, data: result } = await fetchDeleteCjTask(transDeleteParams([id]));
  if (!error && result) {
    await onDeleted();
  }
}

async function handleBatchDelete() {
  const { error, data: result } = await fetchDeleteCjTask(transDeleteParams(checkedRowKeys.value));
  if (!error && result) {
    await onBatchDeleted();
  }
}

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务方法 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

/** 计算动态列宽 */

// 简单列名数组
const simpleCols: string[] = [
  'projectName',
  'orgName',
  'code',
  'provinceName',
  'cityName',
  'countyName',
  'town',
  'village',
  'team',
  'wgs84Longitude',
  'wgs84Latitude',
  'wgs84Altitude',
  'soilTypeLabel',
  'cropTypeLabel'
];
// 表格滚动宽度
const tableScrollWidth = ref<number>(962);
// 原始列宽
let originColWidths: any = {};
// 动态列宽字典
let dynamicColWidths: any = {};
// 是否初始化原始列宽
let originColWidthsInited = false;
// 临时页面元素
let tempDiv: any = null;
let tempSpan: any = null;
// 临时滚动宽度
let tempScrollWidth: number = 0;
// 创建临时页面元素
function createSpan() {
  const wrapper = document.createElement('div');
  wrapper.style.visibility = 'hidden';
  wrapper.style.whiteSpace = 'nowrap';
  wrapper.style.overflow = 'hidden';
  const span = document.createElement('span');
  span.style.visibility = 'visible';
  span.style.display = 'inline-block';
  wrapper.appendChild(span);
  tempDiv = wrapper;
  tempSpan = span;
  const firstHeader = document.getElementsByClassName('n-data-table-th__title')[0];
  firstHeader.appendChild(tempDiv);
}
// 计算文本宽度
function calcTextWidth(content: string): number {
  tempSpan.textContent = content;
  return tempSpan.offsetWidth;
}
// 计算列宽
function calcColWidth(col: any, content: string) {
  if (simpleCols.includes(col.key)) {
    if (!originColWidthsInited) {
      originColWidths[col.key] = col.width;
    }
    const w = calcTextWidth(content) + 20;
    dynamicColWidths[col.key] = Math.max(dynamicColWidths[col.key] || 0, w);
  }
}
// 更新动态列宽和表格滚动宽度
function setCalcWidth(column: any) {
  if (dynamicColWidths[column.key]) {
    column.width = Math.max(originColWidths[column.key], dynamicColWidths[column.key]);
  }
  tempScrollWidth += column.width;
}
// 更新列宽
function updateColumnsWidth(rows: any) {
  // 重置相关变量
  if (!tempDiv) {
    createSpan();
  }
  if (!originColWidthsInited) {
    originColWidths = {};
  }
  dynamicColWidths = {};
  tempScrollWidth = 0;
  const tempColumns = [...columns.value];
  // 计算列宽
  rows.records.forEach((row: any) => {
    tempColumns.forEach((column: any) => {
      if (!column.children) {
        calcColWidth(column, `${row[column.key]}`);
      } else {
        column.children.forEach((child1: any) => {
          if (!child1.children) {
            calcColWidth(child1, `${row[child1.key]}`);
          } else {
            child1.children.forEach((child2: any) => {
              calcColWidth(child2, `${row[child2.key]}`);
            });
          }
        });
      }
    });
  });
  // 更新宽度
  tempColumns.forEach((column: any) => {
    if (!column.children) {
      setCalcWidth(column);
    } else {
      column.children.forEach((child1: any) => {
        if (!child1.children) {
          setCalcWidth(child1);
        } else {
          child1.children.forEach((child2: any) => {
            setCalcWidth(child2);
          });
        }
      });
    }
  });
  // 重置滚动宽度，重新加载 columns
  tableScrollWidth.value = tempScrollWidth + 1;
  resetAllColumns(() => tempColumns);
  originColWidthsInited = true;

  // 移除临时元素
  if (tempDiv.parentNode) {
    tempDiv.parentNode.removeChild(tempDiv);
    tempDiv = null;
    tempSpan = null;
  }
}

/** 下载模板 */
async function downloadTemplate() {
  const { error, data: result } = await fetchCjTaskDownloadTemplate();
  if (!error && result) {
    window.open(result);
  }
}

/** 上传数据 */
function uploadData() {
  showImportDataModal();
}

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 框架生命周期 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++

// +++++++++++++++++++++++++++++++++++++++++++++++
// ---------- 业务生命周期 ----------
// +++++++++++++++++++++++++++++++++++++++++++++++
</script>

<template>
  <div class="min-h-500px flex-col-stretch gap-8px overflow-hidden lt-sm:overflow-auto">
    <TaskSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
    <NCard :bordered="false" class="sm:flex-1-hidden card-wrapper" content-class="flex-col">
      <TableHeaderOperation
        v-model:columns="columnChecks"
        :checked-row-keys="checkedRowKeys"
        :loading="loading"
        add-auth="cj:task:add"
        delete-auth="cj:task:delete"
        @add="handleAdd"
        @delete="handleBatchDelete"
        @refresh="getData"
      >
        <template #suffix>
          <template v-if="hasAuth('cj:task:downloadTemplate')">
            <NButton type="primary" size="small" ghost @click="downloadTemplate">
              <template #icon>
                <icon-material-symbols:download class="text-icon" />
              </template>
              下载模板
            </NButton>
            <NButton type="primary" size="small" ghost @click="uploadData">
              <template #icon>
                <icon-material-symbols:upload-rounded class="text-icon" />
              </template>
              上传数据
            </NButton>
          </template>
        </template>
      </TableHeaderOperation>
      <NDataTable
        v-model:checked-row-keys="checkedRowKeys"
        remote
        striped
        size="small"
        class="sm:h-full"
        :data="data"
        :scroll-x="tableScrollWidth"
        :columns="columns"
        :flex-height="!appStore.isMobile"
        :loading="loading"
        :single-line="false"
        :row-key="row => row.id"
        :pagination="mobilePagination"
      />
      <TaskOperateDrawer v-model:visible="drawerVisible" :operate-type="operateType" :row-data="editingData" @submitted="getDataByPage" />
      <TaskImportDataModal v-model:visible="importDataModalVisible" @submitted="getData" />
    </NCard>
  </div>
</template>
